package com.iwhalecloud.bss.kite.cucc.web.controller.order;

import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.inf.IInfServiceBus;
import com.iwhalecloud.bss.kite.cucc.client.api.inf.IInfUnifyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.iwhalecloud.bss.kite.client.dto.DataResult;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.order.IAttachmentService;
import com.iwhalecloud.bss.kite.cucc.client.dto.inf.req.QryStockAttachMentUrlReqDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.inf.rsp.QryStockAttachMentUrlRspDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.order.ContractDictionaryDTO;
import com.iwhalecloud.bss.kite.cucc.client.vo.order.FileVO;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.DcSystemParamCache;
import com.iwhalecloud.bss.kite.dataservice.entity.DcPublic;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

import com.ztesoft.bss.base.annotation.IgnoreSession;
import com.ztesoft.bss.common.bo.LoginInfo;
import com.ztesoft.bss.common.util.ContextUtil;

@RestController
@RequestMapping("/attachment")
@Api(tags = { "/attachment - 附件(通用文件上传、预览)" })
public class AttachmentController {

    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private IInfServiceBus infServiceBus;
    @Autowired
    private IInfUnifyService infUnifyService;
    @Autowired
    IQuerySceneInstService querySceneInstService;

    @ApiOperation(value = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径", notes = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径")
    @PostMapping(produces = "application/json;charset=utf-8")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "file", required = true, dataType = "file", paramType = "form") })
    public DataResult<FileVO> uploadatTachment(HttpServletRequest request,
            @RequestParam(value = "file", required = true) MultipartFile file) {
        byte[] bytes = null;
        try {
            bytes = file.getBytes();
        } catch (IOException e) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("附件上传异常");
        }
        return ErrorConsts.SUCCESS.getResult(attachmentService.uploadAttachment(file.getOriginalFilename(), bytes));
    }

    @ApiOperation(value = "附件预览（适用于所有文件预览）、返回文件路径", notes = "附件预览（适用于所有文件预览）、返回文件路径")
    @GetMapping
    public DataResult<String> attachView(String fileId, String fileName, boolean isStockAttachment) {
        return ErrorConsts.SUCCESS.getResult(attachmentService.attachView(fileId, fileName, isStockAttachment));
    }

    @ApiOperation(value = "附件预览（适用于存量附件预览）、返回文件路径", notes = "附件预览（适用于存量附件预览）、返回文件路径")
    @GetMapping("stockAttach")
    public DataResult<String> stockAttachView(String fileId) {
        QryStockAttachMentUrlReqDTO qryStockAttachMentUrlReqDTO = new QryStockAttachMentUrlReqDTO();
        LoginInfo loginInfo = ContextUtil.getLoginInfo();
        qryStockAttachMentUrlReqDTO.setProvinceCode(loginInfo.getUserInfo().getPostProvinceNbr());
        qryStockAttachMentUrlReqDTO.setEsbFileName(fileId);
        QryStockAttachMentUrlRspDTO qryStockAttachMentUrlRsp = attachmentService
            .getStockAttachmentUrl(qryStockAttachMentUrlReqDTO);
        String result = "";
        if (!KiteObjectUtils.isEmpty(qryStockAttachMentUrlRsp)) {
            result = qryStockAttachMentUrlRsp.getUrl();
        }
        return ErrorConsts.SUCCESS.getResult(result);
    }

    @ApiOperation(value = "附件字典查询（只是查询附件的字典）", notes = "附件字典查询（只是查询附件的字典）")
    @GetMapping("dictionary")
    public DataResult<List<ContractDictionaryDTO>> queryContractDictionary() {
        return ErrorConsts.SUCCESS.getResult(attachmentService.queryContractDictionary());
    }
    @ApiOperation(value = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径", notes = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径")
    @PostMapping(produces = "application/json;charset=utf-8", value = "/orderCenterFileUpload")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "file", required = true, dataType = "file", paramType = "form") })
    public DataResult<FileVO> orderCenterFileUpload(HttpServletRequest request,
                                                    @RequestParam(value = "file", required = true) MultipartFile file) {
        checkFileTypeOrderCenter(file,Optional.ofNullable(DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE_BLACK")).orElse(""),DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE"));
        return ErrorConsts.SUCCESS.getResult(upOrderCenterFile(file));
    }
    @ApiOperation(value = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径", notes = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径")
    @PostMapping(produces = "application/json;charset=utf-8", value = "/orderCenterFilesUpload")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "file", required = true, dataType = "file", paramType = "form") })
    public DataResult<List<FileVO>> orderCenterFilesUpload(HttpServletRequest request,
                                                           @RequestParam(value = "files", required = true) MultipartFile[] files) {
        List<FileVO> fileVOS = new ArrayList<>();
        if(Objects.nonNull(files)&&files.length>0){
            //先检查上传文件是否合法
            for(MultipartFile file : files){
                checkFileTypeOrderCenter(file,Optional.ofNullable(DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE_BLACK")).orElse(""),DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE"));
            }
            for(MultipartFile file : files) {
                fileVOS.add(upOrderCenterFile(file));
            }
        }
        return ErrorConsts.SUCCESS.getResult(fileVOS);
    }
    /**
     * 删除本地临时文件
     * @param file
     */
    public static void delteTempFile(File file) {
        if (file != null) {
            File del = new File(file.toURI());
            del.delete();
        }
    }
    @ApiOperation(value = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径", notes = "附件上传（适用于所有符合特定文件格式上传）、返回文件路径")
    @PostMapping(produces = "application/json;charset=utf-8", value = "/orderCenterHttpFileUpload")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "file", required = true, dataType = "file", paramType = "form") })
    public DataResult<FileVO> orderCenterHttpFileUpload(HttpServletRequest request,
                                                        @RequestParam(value = "file", required = true) MultipartFile file,@RequestParam(value = "contractType", required = false) String contractType) {

        checkFileTypeMarketCenter(file,DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE"));
        FileVO fileVO = upMarketCenterFile(file,contractType);
        return ErrorConsts.SUCCESS.getResult(fileVO);
    }
    @ApiOperation(value = "附件上传（适用于所有符合特定文件格式上传,批量上传）、返回文件路径", notes = "附件上传（适用于所有符合特定文件格式上传批量）、返回文件路径")
    @PostMapping(produces = "application/json;charset=utf-8", value = "/orderCenterHttpFilesUpload")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "file", value = "file", required = true, dataType = "file", paramType = "form") })
    public DataResult<List<FileVO>> orderCenterHttpFilesUpload(HttpServletRequest request,
                                                               @RequestParam(value = "files", required = true) MultipartFile[] files,@RequestParam(value = "contractType", required = false) String contractType) {
        List<FileVO> fileVOS= new ArrayList<>();
        if(files!=null && files.length>0){
            String upload_file_type = DcSystemParamCache.getDcParamVal("UPLOAD_FILE_TYPE");
            //检查文件类型 有不通过则提示报错
            for (MultipartFile file : files){
                checkFileTypeMarketCenter(file,upload_file_type);
            }
            for(MultipartFile file : files){
                fileVOS.add(upMarketCenterFile(file,contractType));
            }
        }
        return ErrorConsts.SUCCESS.getResult(fileVOS);
    }
    private void checkFileTypeMarketCenter(MultipartFile file, String checkType){
        String fileName = file.getOriginalFilename();
        String fileType = KiteStringUtils.substring(fileName, fileName.lastIndexOf('.') + 1);
        if (!KiteStringUtils.contains(checkType, fileType)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("只允许上传指定类型文件");
        }
    }
    private FileVO upMarketCenterFile(MultipartFile file,String contractType){
        String fileName = file.getOriginalFilename();
        FileVO fileVO = new FileVO();
        try {
            byte[] bytes = null;
            String fileId = null;
            bytes = file.getBytes();
            List<JSONObject> fileList = null;
            String up_file_req_type = DcSystemParamCache.getDcParamVal("UP_FILE_REQ_TYPE");
            if(KiteStringUtils.isEmpty(up_file_req_type) || KiteStringUtils.equals(up_file_req_type,"0")){
                File toFile = null;
                if ("".equals(file) || file.getSize() <= 0) {
                    file = null;
                } else {
                    InputStream ins = null;
                    ins = file.getInputStream();
                    toFile = new File(file.getOriginalFilename());
                    inputStreamToFile(ins, toFile);
                    ins.close();
                }
                fileList = attachmentService.orderCenterHttpFileUpload(toFile,bytes);
                delteTempFile(toFile);
            }else {
                Map<String,String> req = new HashMap<>();
                req.put("FILE_NAME",fileName);
                req.put("INFO_TYPE","contract");
/*                if(KiteStringUtils.equals(contractType,"01")){
                    req.put("SUBINFO_TYPE","oppo_syn_contract");
                }else if(KiteStringUtils.equals(contractType,"02")){
                    req.put("SUBINFO_TYPE","presale_agreement");
                }else if(KiteStringUtils.equals(contractType,"03")){
                    req.put("SUBINFO_TYPE","print_contract");
                }*/
                fileVO =  infUnifyService.marketCenterFileUpload(req,bytes);
                fileVO.setFileName(fileName);
                fileVO.setState("200"); // 成功返回200，失败返回其他
                return fileVO;
            }
            if(KiteListUtils.isNotEmpty(fileList)){
                fileId=KiteMapUtils.getString(fileList.get(0), "location");
                fileVO.setFileId(fileId);
                fileVO.setAccessoryId(KiteMapUtils.getString(fileList.get(0), "flowId"));
                fileVO.setFileName(fileName);
                fileVO.setState("200"); // 成功返回200，失败返回其他
            }
        } catch (IOException e) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("附件上传失败");
        }
        return fileVO;
    }

    private FileVO upOrderCenterFile(MultipartFile file){
        String fileName = file.getOriginalFilename();
        FileVO fileVO = new FileVO();
        if(KiteStringUtils.isNotEmpty(fileName)){
            String fileType = KiteStringUtils.substring(fileName, fileName.lastIndexOf('.') + 1);
            byte[] bytes = null;
            String fileId = null;
            try {
                bytes = file.getBytes();
                fileId = attachmentService.orderCenterFileUpload(fileName, bytes, fileType);
                fileVO.setFileId(fileId);
                fileVO.setFileName(fileName);
                fileVO.setState("200"); // 成功返回200，失败返回其他
            } catch (IOException e) {
                ErrorConsts.BUSI_COMMON_ERROR.throwOut("附件上传失败");
            }
        }
        return fileVO;
    }

    private void checkFileTypeOrderCenter(MultipartFile file,String blackType,String checkType){
        String fileName = file.getOriginalFilename();
        /**
         * add by ma.junjun
         * 2022-01-22
         * 任意文件上传安全漏洞修改:校验方式，通过文件名拆分，如果存在php,exe,asp等则终止上传操作
         * 增加黑名单【避免如：xxx.php.jpeg,xx.exe.png,xxx.phpxxx.jpeg,xxx.php.png 等格式】
         * begin
         */
        if(KiteStringUtils.isNotEmpty(fileName)){
            String [] fileNames =  fileName.split("\\.");
            String [] fileBlack = blackType.split(",")  ;
            boolean cycleEndFlag = false ;
            //如果未配置黑名单，则不用校验
            if( (fileBlack !=null && fileBlack.length > 0) && (fileNames != null && fileNames.length >0)){
                for(String temp :fileNames){
                    //出现如：xxx.php000.jpeg,xxx.php000.png等格式的安全漏洞，需要调整为根据名称去模糊匹配配置的黑名单
                    for(String black :fileBlack){
                        if(temp !=null && temp.toLowerCase().contains(black) ){
                            cycleEndFlag =true;
                            ErrorConsts.BUSI_COMMON_ERROR.throwOut("只允许上传指定类型文件");
                            break;
                        }
                    }
                    if(cycleEndFlag){
                        break;
                    }
                }
            }
        }
        /**
         * add by ma.junjun
         * 2022-01-22
         * 任意文件上传安全漏洞修改:校验方式，通过文件名拆分，如果存在php,exe,asp等则终止上传操作
         * 增加黑名单【避免如：xxx.php.jpeg,xx.exe.png,xxx.phpxxx.jpeg,xxx.php.png 等格式】
         * end
         */
        String fileType = KiteStringUtils.substring(fileName, fileName.lastIndexOf('.') + 1);
        if (!KiteStringUtils.contains(checkType, fileType)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("只允许上传指定类型文件");
        }
    }
    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try(OutputStream os = new FileOutputStream(file);){
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            ErrorConsts.SYSTEM_ERROR.throwOut(e.getMessage()); // e.printStackTrace();
        }finally {
            try {
                ins.close();
            } catch (IOException e) {
                ErrorConsts.SYSTEM_ERROR.throwOut(e.getMessage());
            }
        }
    }
    @ApiOperation(value = "导出模板")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "downName", value = "文件名", required = true),
        @ApiImplicitParam(name = "urlAddress", value = "文件相对路径", required = true)
    })
    @GetMapping(value = "/downloadTemplate")
    public DataResult<Map<String, Object>> downloadFile(String downName, String urlAddress, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> result = new HashMap<>();
        InputStream is = null;
        OutputStream os = null;
        try {
            Map<String, String> map = System.getenv();
            // 获取本机用户名
            String userName = map.get("USERNAME");
            // 获取打包后的文件路径
            is = this.getClass().getClassLoader().getResourceAsStream(urlAddress);
            String houZuiName = urlAddress.substring(urlAddress.lastIndexOf("."));
            //下载到本机展示的文件名称
            downName = "C:\\Users\\" + userName + "\\Downloads\\" + downName + houZuiName;
            os = new FileOutputStream(downName);
            byte bf[] = new byte[1024];
            int length = 0;
            while ((length = is.read(bf, 0, 1024)) != -1) {
                os.write(bf, 0, length);
            }
//            is.close();
//            os.close();
            result.put("0", "下载成功");
        } catch (Exception e) {
            result.put("1", "下载失败");
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }
        return ErrorConsts.SUCCESS.getResult(result);
    }

    @ApiOperation(value = "导出模板")
    @ApiImplicitParams( {
        @ApiImplicitParam(name = "localFileName", value = "文件名", required = true),
    })
    @IgnoreSession
    @GetMapping(value = "/downloadLocalFile")
    public void downloadLocalFile(String localFileName, HttpServletResponse res, HttpServletRequest req) throws Exception {
        Map<String, Object> result = new HashMap<>();
        FileInputStream instream = null;
        try {
            String localFilepath = getClass().getResource("/templatedownload/" + localFileName).getPath();
            res.setContentType("multipart/form-data");
            res.setCharacterEncoding("UTF-8");
            res.setContentType("text/html");

            String userAgent = req.getHeader("User-Agent");
            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                localFileName = java.net.URLEncoder.encode(localFileName, "UTF-8");
            }
            else {
                localFileName = new String((localFileName).getBytes("UTF-8"), "ISO-8859-1");
            }
            res.setHeader("Content-Disposition", "attachment;fileName=" + localFileName);
            localFilepath = URLDecoder.decode(localFilepath, "UTF-8");
            instream = new FileInputStream(localFilepath);
            ServletOutputStream outstream = res.getOutputStream();
            int b = 0;
            byte[] buffer = new byte[1024];
            while ((b = instream.read(buffer)) != -1) {
                outstream.write(buffer, 0, b);
            }
//            instream.close();

            if (outstream != null) {
                outstream.flush();
                outstream.close();
            }
            result.put("0", "下载成功");
        }
        catch (Exception e) {
            result.put("1", "下载失败");
        }finally {
            if (instream != null) {
                try {
                    instream.close();
                } catch (IOException e) {
//                    e.printStackTrace();
                }
            }
        }
//        return ErrorConsts.SUCCESS.getResult(result);
    }


    @ApiOperation(value = "下载excel导入模板")
    @ApiImplicitParams( {
        @ApiImplicitParam(name = "sceneInstId", value = "场景实例id", required = true),
    })
    @IgnoreSession
    @GetMapping(value = "/downloadImportFile")
    public void downloadImportFile(String sceneInstId, HttpServletResponse res, HttpServletRequest req,
                                   String importType) throws Exception {
        Map<String, Object> result = new HashMap<>();
        FileInputStream instream = null;
        try {
            if (KiteStringUtils.isEmpty(importType)) {
                importType = querySceneInstService.getCommonAttrValue(sceneInstId, "importType");
            }
            if (KiteStringUtils.isEmpty(importType)) {
                //                BssException.throwOut("","","导入类型为空，请检查");
                importType = "1000"; // 收入归集集团创建导入模版没有导入类型
            }
            DcPublic file = DcPublicCache.get("20210303001", importType);
            String localFileName = file.getCodea();
            if (KiteStringUtils.equals(file.getPcode(), "2")) {
                localFileName = localFileName+".xls";
            }
            else {
                localFileName = localFileName+".xlsx";
            }
            String localFilepath = getClass().getResource("/templatedownload/" + localFileName).getPath();
            res.setContentType("multipart/form-data");
            res.setCharacterEncoding("UTF-8");
            res.setContentType("text/html");

            String userAgent = req.getHeader("User-Agent");
            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                localFileName = java.net.URLEncoder.encode(localFileName, "UTF-8");
            }
            else {
                localFileName = new String((localFileName).getBytes("UTF-8"), "ISO-8859-1");
            }
            res.setHeader("Content-Disposition", "attachment;fileName=" + localFileName);
            localFilepath = URLDecoder.decode(localFilepath, "UTF-8");
            instream = new FileInputStream(localFilepath);
            ServletOutputStream outstream = res.getOutputStream();
            int b = 0;
            byte[] buffer = new byte[1024];
            while ((b = instream.read(buffer)) != -1) {
                outstream.write(buffer, 0, b);
            }
//            instream.close();

            if (outstream != null) {
                outstream.flush();
                outstream.close();
            }
            result.put("0", "下载成功");
        }
        catch (Exception e) {
            result.put("1", "下载失败");
        }finally {
            if (instream != null) {
                try {
                    instream.close();
                } catch (IOException e) {
//                    e.printStackTrace();
                }
            }
        }
//        return ErrorConsts.SUCCESS.getResult(result);
    }
}
